package fun.werfamily.wf.gateway.filter;

import fun.werfamily.wf.gateway.util.TokenUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

/**
 * Created with IntelliJ IDEA.
 *
 * @Author: Mr.WenMing Zhang
 * @Date: 2023-04-05 11:07
 * @Description: 认证授权全局过滤器
 */
@Slf4j
@Component
@Order(value = Integer.MIN_VALUE)
public class AuthorizeGlobalFilter implements GlobalFilter {

    @Resource
    private TokenUtil tokenUtil;

    private static final String AUTHORIZE_TOKEN = "Authorization";

    private static final String PERMIT_PATH_REGEX = "/login|open/";

    private static List<String> permitPathList;

    static {
        permitPathList = new ArrayList<>();
        permitPathList.add("login");
        permitPathList.add("open");
        permitPathList.add("VerifyCode");
        permitPathList.add("register");
    }

    private boolean isPermit(String path){
        boolean isPermit = false;
        for (String permitPath : permitPathList) {
            if (path.contains(permitPath)) {
                isPermit = true;
                break;
            }
        }
        return isPermit;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // filter的前置处理
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        InetSocketAddress remoteAddress = request.getRemoteAddress();
        String path = request.getPath().pathWithinApplication().value();
        if (!isPermit(path)) {
            HttpHeaders headers = request.getHeaders();
            //从请求头中获取token
            String token = headers.getFirst(AUTHORIZE_TOKEN);
            if (token == null) {
                //从请求头参数中获取token
                token = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);
            }

            //如果token为空，直接返回401，未授权
            if (StringUtils.isEmpty(token)) {
                log.warn("【JWT TOKEN】token为空,未授权,请求路径:{},远程IP地址:{}", path, remoteAddress);
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //处理完成，直接拦截，不再进行下去
                return response.setComplete();
            }

            // 校验token是否有效
            if (!tokenUtil.validateToken(request)) {
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                //处理完成，直接拦截，不再进行下去
                return response.setComplete();
            }
        }else {
            log.info("无需授权校验,放行{},{}", remoteAddress, path);
        }
        return chain
                // 继续调用filter
                .filter(exchange)
                // filter的后置处理
                .then(Mono.fromRunnable(() -> {
                    HttpStatusCode statusCode = response.getStatusCode();
                    log.info("请求路径:{},远程IP地址:{},响应码:{}", path, remoteAddress, statusCode);
                }));
    }
}
